package com.csaba.swing.gui;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.net.URL;
import java.text.DateFormat;
import java.util.Date;

import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.SwingConstants;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;

import com.csaba.connector.model.Amount;
import com.csaba.connector.model.HistoryItem;
import com.csaba.swing.MainWindow;
import com.csaba.swing.action.ActionFactory;
import com.csaba.swing.action.TransactionFilterAction;
import com.csaba.swing.gui.util.DynamicColumnLayout;
import com.csaba.swing.gui.util.TableSizeContainer;
import com.csaba.swing.gui.util.TableSorter;
import com.csaba.swing.gui.util.WindowSizeContanier;
import com.csaba.swing.model.AmountComparator;
import com.csaba.swing.model.TransactionFilter;
import com.csaba.util.Formatters;

@SuppressWarnings( "serial" )
public class TransactionListView extends JInternalFrame
{
	private static String[] HEADERS = new String[] {
			MainWindow.getString("TransactionListView.header.date"), MainWindow.getString("TransactionListView.header.bank"), MainWindow.getString("TransactionListView.header.customer"), MainWindow.getString("TransactionListView.header.account"), MainWindow.getString("TransactionListView.header.description"), MainWindow.getString("TransactionListView.header.amount"), //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$
			MainWindow.getString("TransactionListView.header.balance"), }; //$NON-NLS-1$
	private static Class<?>[] COLUMN_CLASS = new Class<?>[] { Date.class, ImageIcon.class, String.class, String.class,
			String.class, Amount.class, Amount.class, };

	JLabel bank;
	JLabel customerName;
	JLabel account;
	JLabel dateRange;

	JTable transactions;

	JLabel allCredit;
	JLabel allDebit;
	JLabel all;

	HistoryItem[] items;
	TransactionFilter filter;

	public TransactionListView()
	{
		super(MainWindow.getString("TransactionListView.title"), true, true, true, true); //$NON-NLS-1$
		setDefaultCloseOperation(JInternalFrame.DISPOSE_ON_CLOSE);
		if ( !WindowSizeContanier.getInstance().monitorComponent(this) )
			setSize(600, 350);
		setFrameIcon(GUIContext.getIcon("transactions", 16)); //$NON-NLS-1$

		//init layout
		final JPanel general = new JPanel(new DynamicColumnLayout(new int[] { DynamicColumnLayout.RIGHT,
				DynamicColumnLayout.LEFT }));
		general.add(new JLabel(MainWindow.getString("TransactionListView.bank"))); //$NON-NLS-1$
		general.add(bank = new JLabel("")); //$NON-NLS-1$

		general.add(new JLabel(MainWindow.getString("TransactionListView.customer"))); //$NON-NLS-1$
		general.add(customerName = new JLabel("")); //$NON-NLS-1$
		general.add(new JLabel(MainWindow.getString("TransactionListView.account"))); //$NON-NLS-1$
		general.add(account = new JLabel("")); //$NON-NLS-1$
		general.add(new JLabel(MainWindow.getString("TransactionListView.dateRange"))); //$NON-NLS-1$
		general.add(dateRange = new JLabel("")); //$NON-NLS-1$

		final JPanel buttons = new JPanel();
		final JButton filter = new JButton(
				new AbstractAction(MainWindow.getString("TransactionListView.button.filter")) //$NON-NLS-1$
				{

					@Override
					public void actionPerformed( final ActionEvent arg0 )
					{
						filter();
					}

				});
		buttons.add(filter);
		final JButton close = new JButton(new AbstractAction(MainWindow.getString("TransactionListView.button.close")) //$NON-NLS-1$
				{

					@Override
					public void actionPerformed( final ActionEvent arg0 )
					{
						dispose();
					}

				});
		buttons.add(close);

		final JPanel data = new JPanel(new BorderLayout());

		final HistoryItemModel him = new HistoryItemModel();
		final TableSorter sorter = new TableSorter(him);
		sorter.setColumnComparator(Amount.class, new AmountComparator());
		transactions = new JTable(sorter);
		transactions.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		sorter.setTableHeader(transactions.getTableHeader());

		transactions.addMouseListener(new MouseAdapter()
		{
			@Override
			public void mouseClicked( final MouseEvent e )
			{
				// show transaction's details
				if ( e.getClickCount() > 1 )
				{//handle as double click
					final int index = transactions.getSelectedRow();
					final HistoryItem item = ( (HistoryItemModel) ( (TableSorter) transactions.getModel() )
							.getTableModel() ).getHistoryItemAt(index);
					final TransactionView view = new TransactionView();
					MainWindow.getDesktop().add(view);
					view.showIt(item);
				}
			}

		});

		final JScrollPane scrollPane = new JScrollPane(transactions);
		transactions.setFillsViewportHeight(true);
		data.add(scrollPane, BorderLayout.CENTER);
		final DefaultTableCellRenderer amountRenderer = new DefaultTableCellRenderer();
		amountRenderer.setHorizontalAlignment(SwingConstants.RIGHT);
		transactions.setDefaultRenderer(Amount.class, amountRenderer);

		final JPanel summary = new JPanel(new DynamicColumnLayout(new int[] { DynamicColumnLayout.RIGHT,
				DynamicColumnLayout.LEFT }));
		summary.add(new JLabel(MainWindow.getString("TransactionListView.totalCredits"))); //$NON-NLS-1$
		summary.add(allCredit = new JLabel("")); //$NON-NLS-1$
		summary.add(new JLabel(MainWindow.getString("TransactionListView.totalDebits"))); //$NON-NLS-1$
		summary.add(allDebit = new JLabel("")); //$NON-NLS-1$
		summary.add(new JLabel(MainWindow.getString("TransactionListView.grandTotal"))); //$NON-NLS-1$
		summary.add(all = new JLabel("")); //$NON-NLS-1$
		data.add(summary, BorderLayout.SOUTH);

		final JPanel contentPane = (JPanel) getContentPane();
		contentPane.setBorder(BorderFactory.createEmptyBorder());
		contentPane.setLayout(new BorderLayout());
		contentPane.add(general, BorderLayout.NORTH);
		contentPane.add(buttons, BorderLayout.SOUTH);
		contentPane.add(data, BorderLayout.CENTER);
	}

	protected void filter()
	{
		final TransactionFilterAction action = (TransactionFilterAction) ActionFactory
				.getAction(TransactionFilterAction.class);
		action.updateView(filter, this);
	}

	private void setField( final JLabel label, final Object value )
	{
		if ( value == null )
			label.setText(MainWindow.getString("TransactionListView.noFilter")); //$NON-NLS-1$
		else
			label.setText(value.toString());
	}

	public void showIt( final TransactionFilter filter, final HistoryItem[] items )
	{
		this.items = items;
		this.filter = filter;

		setField(this.bank, filter.getBank());
		setField(this.customerName, filter.getCustomer());
		setField(this.account, filter.getAccount());

		final DateFormat dateFormat = Formatters.getShortDateFormat();
		dateRange.setText(dateFormat.format(filter.getFrom()) + " - " + dateFormat.format(filter.getTo())); //$NON-NLS-1$

		final TableSorter sorter = (TableSorter) transactions.getModel();
		sorter.setTableModel(new HistoryItemModel(items));

		Amount totalCredit = null;
		Amount totalDebit = null;
		Amount total = null;
		try
		{
			for ( final HistoryItem item : items )
			{
				final Amount amount = item.getAmount();
				if ( amount.getAmount() > 0 )
				{
					totalCredit = amount.add(totalCredit);
				}
				else
				{
					totalDebit = amount.add(totalDebit);
				}
				total = amount.add(total);

			}
			if ( totalCredit == null )
				allCredit.setText("-"); //$NON-NLS-1$
			else
				allCredit.setText(totalCredit.toString());

			if ( totalDebit == null )
				allDebit.setText("-"); //$NON-NLS-1$
			else
				allDebit.setText(totalDebit.toString());

			if ( total == null )
				all.setText("-"); //$NON-NLS-1$
			else
				all.setText(total.toString());
		}
		catch ( final IllegalArgumentException e )
		{
			allCredit.setText(MainWindow.getString("TransactionListView.differentCurrencies")); //$NON-NLS-1$
			allDebit.setText(MainWindow.getString("TransactionListView.differentCurrencies")); //$NON-NLS-1$
			all.setText(MainWindow.getString("TransactionListView.differentCurrencies")); //$NON-NLS-1$
		}
		setVisible(true);
		TableSizeContainer.getInstance().monitorTable("TransactionListView.transactions", transactions); //$NON-NLS-1$
	}

	class HistoryItemModel extends AbstractTableModel
	{
		private HistoryItem[] items;

		public HistoryItemModel( final HistoryItem[] items )
		{
			super();
			this.setItems(items);
		}

		public HistoryItemModel()
		{
			super();
			setItems(new HistoryItem[0]);
		}

		@Override
		public int getColumnCount()
		{
			return HEADERS.length;
		}

		@Override
		public int getRowCount()
		{
			return getItems().length;
		}

		@Override
		public Class<?> getColumnClass( final int columnIndex )
		{
			return COLUMN_CLASS[columnIndex];
		}

		@Override
		public Object getValueAt( final int rowIndex, final int columnIndex )
		{
			final HistoryItem item = getItems()[rowIndex];
			Object result = null;
			switch ( columnIndex )
			{
			case 0:
				result = item.getDate();
				break;
			case 1:
				final URL icon = item.getOwner().getBank().getSmallIcon();
				if ( icon != null )
					result = GUIContext.getIcon(icon);
				break;
			case 2:
				result = item.getOwner().getCustomer().getName();
				break;
			case 3:
				result = item.getOwner().getNumber();
				break;
			case 4:
				result = item.getDescription();
				break;
			case 5:
				result = item.getAmount();
				break;
			case 6:
				result = item.getBalance();
				break;
			}
			return result;
		}

		public HistoryItem getHistoryItemAt( final int row )
		{
			return getItems()[row];
		}

		@Override
		public boolean isCellEditable( final int rowIndex, final int columnIndex )
		{
			// this is a read only model
			return false;
		}

		@Override
		public String getColumnName( final int column )
		{
			return HEADERS[column];
		}

		public void setItems( final HistoryItem[] items )
		{
			this.items = items;
			fireTableDataChanged();
		}

		public HistoryItem[] getItems()
		{
			return items;
		}

	}
}
